package com.ruoyi.flow.service.impl;

import com.ruoyi.flow.entity.Constant;
import com.ruoyi.flow.entity.event.FlowEvent;
import com.ruoyi.flow.entity.event.NodeEvent;
import com.ruoyi.flow.entity.machine.*;
import com.ruoyi.flow.service.FlowEventService;
import com.ruoyi.flow.service.FlowMachineService;
import com.ruoyi.flow.service.FlowUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class FlowEventServiceImpl implements FlowEventService {

    @Autowired
    private FlowUserService flowUserService;

    @Autowired
    private FlowMachineService flowMachineService;

    /**
     * 获取流程事件（特殊事件：非流程事件）
     *
     * @param machineId
     * @return
     */
    @Override
    public FlowEvent getFlowEvent(String machineId) {
        Flow flow = flowMachineService.getFlow(machineId);

        FlowEvent flowEvent = new FlowEvent(flow);
        for (Node node : flow.getNodes()) {
            flowEvent.getNodeEvents().add(getNodeEvent(flow, node));
        }
        for (NodeEvent nodeEvent : flowEvent.getNodeEvents()) {
            flowEvent.getEvents().addAll(nodeEvent.getEvents());
        }

        //非流程事件
        List<Event> otherEvents = flow.getEvents().stream().filter(x -> Constant.EventType.OTHER.equals(x.getType())).collect(Collectors.toList());
        flowEvent.getEvents().addAll(otherEvents);
        //开始事件
        List<Event> startEvents = flow.getEvents().stream().filter(x -> "add".equalsIgnoreCase(x.getId()) || Constant.Event.START.equalsIgnoreCase(x.getId())).collect(Collectors.toList());
        flowEvent.getEvents().addAll(startEvents);


        return flowEvent;
    }

    /**
     * 获取节点事件（特殊事件：拿回）
     *
     * @param machineId
     * @param nodeId
     * @return
     */
    @Override
    public NodeEvent getNodeEvent(String machineId, String nodeId) {
        Flow flow = flowMachineService.getFlow(machineId);
        Node node = flow.getNodeById(nodeId);
        return getNodeEvent(flow, node);
    }

    /**
     * 获取节点事件（特殊事件：拿回）
     *
     * @param flow
     * @param node
     * @return
     */
    @Override
    public NodeEvent getNodeEvent(Flow flow, Node node) {

        Set<Event> events = new HashSet<>();

        List<Line> lines = flow.getLines().stream().filter(x -> x.getSource().equals(node.getId())).collect(Collectors.toList());

        for (Line line : lines) {
            String on = line.getOn();
            List<Handler> handlers = line.getHandlers();
            if (handlers == null || handlers.size() == 0) {
                handlers = node.getHandlers();
            }
            //判断权限
            if (checkUser(handlers)) {
                Event event = flow.getEventById(on);
                if (event != null) {
                    events.add(event);
                }
            }
        }

        //拿回事件（拿回事件无法确定权限，只能在运行时再次判断权限）
        if (Constant.Bool.YES.equals(node.getBack())) {

            List<Line> lines1 = flow.getLines().stream().filter(x -> x.getTarget().equals(node.getId())).collect(Collectors.toList());
            for (Line line : lines1) {
                List<Handler> handlers = line.getHandlers();
                if (handlers == null || handlers.size() == 0) {
                    handlers = node.getHandlers();
                }
                //判断权限
                if (checkUser(handlers)) {
                    Event event = flow.getEventById(Constant.Event.BACK);
                    if (event == null) {
                        //虚拟一个拿回事件
                        event = new Event();
                        event.setId(Constant.Event.BACK);
                        event.setName("拿回");
                        event.setType(Constant.EventType.OPERATE);
                        event.setOperate(Constant.Event.BACK);
                    }
                    if (event != null) {
                        events.add(event);
                    }
                    break;
                }
            }

        }

        NodeEvent nodeEvent = new NodeEvent(node);
        nodeEvent.setEvents(events);

        return nodeEvent;
    }

    private boolean checkUser(List<Handler> handlers) {
        return flowUserService.checkUser(handlers);
    }


}
